package com.ruoyi.tcp;

import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.tcp.client.ClientCustomerHandler;
import com.ruoyi.tcp.domain.CardReader;
import com.ruoyi.tcp.entity.beat.BeatEntity;
import com.ruoyi.tcp.messager.CustomerMessageDecoder;
import com.ruoyi.tcp.messager.CustomerMessageEncoder;
import com.ruoyi.tcp.service.ICardReaderService;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

@RequiredArgsConstructor
@Component
public class TcpClientRunner implements ApplicationRunner {


    private Bootstrap bootstrap = new Bootstrap();

    ExecutorService executorService = Executors.newFixedThreadPool(20);



    @Getter
    public static class ClientChannel {

        private Long channelNo;
        private String password;
        private Integer version;
        private String deviceSerializeNumber;
        private Long deviceNumber;
        private AtomicLong serialNumber;
        //经度
        private Integer longitude;
        //纬度
        private Integer latitude;
        private String host;
        private Integer port;
    }

    public static final TcpClientRunner.ClientChannel clientChannel;

    static {
        clientChannel = new TcpClientRunner.ClientChannel();
        clientChannel.version = 2;
        clientChannel.channelNo = 1281L;
        clientChannel.password = "F0I1S2K1D1B0H2A2";
        clientChannel.deviceSerializeNumber = "000000000000000000000000";

        clientChannel.serialNumber = new AtomicLong(1L);

        clientChannel.host = "120.79.151.229";
        clientChannel.port = 6689;
    }

    @Scheduled(fixedRate = 30000) // 每30秒执行一次
    public void performTask() {

        ICardReaderService readerService = SpringUtils.getBean(ICardReaderService.class);
        CardReader cardReader1 = new CardReader();
        cardReader1.setPushType(1);
        List<CardReader> cardReaders = readerService.listAll(cardReader1);
        for (CardReader cardReader : cardReaders) {
            executorService.submit(()->{
                try {
                    ChannelFuture  sync = bootstrap.connect(clientChannel.getHost(), clientChannel.getPort()).sync();
                    Channel channel = sync.channel();
                    channel.writeAndFlush(createBeatEntity(Long.valueOf(cardReader.getSerialNumber()),clientChannel.serialNumber.getAndIncrement()));
                    channel.closeFuture().sync();
//                    System.out.println(Thread.currentThread().getName()+"-->链接已释放");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        bootstrap.group(eventLoopGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new IdleStateHandler(3,0,0));
                        pipeline.addLast(new CustomerMessageDecoder());
                        pipeline.addLast(new CustomerMessageEncoder());
                        pipeline.addLast(new ClientCustomerHandler());
                    }
                });

    }

    public static BeatEntity createBeatEntity(Long deviceNumber, Long dataSerializenumber) {
        BeatEntity beatEntity = new BeatEntity();
        beatEntity.setChannelNo(clientChannel.channelNo);
        beatEntity.setVersion(clientChannel.version);
        beatEntity.setSerializeNumber(dataSerializenumber);
        beatEntity.setTypeStr("0x1");
        beatEntity.setSendTime(LocalDateTime.now());
        beatEntity.setOccurTime(LocalDateTime.now());
        beatEntity.setDeviceNumber(deviceNumber);
        beatEntity.setDeviceSerializeNumber(clientChannel.deviceSerializeNumber);
        byte[] encryptBytes = beatEntity.createEncryptBytes(clientChannel.password);
        beatEntity.setEncryptData(encryptBytes);
        return beatEntity;
    }
}
